package com.ftw.commons.network

import com.ftw.commons.bean.ApiException
import com.ftw.commons.bean.Response
import com.google.gson.Gson
import com.google.gson.TypeAdapter
import com.google.gson.reflect.TypeToken
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okhttp3.ResponseBody
import okio.Buffer
import retrofit2.Converter
import retrofit2.Retrofit
import java.io.OutputStreamWriter
import java.lang.reflect.Type
import java.nio.charset.Charset


/**
 * 描    述：
 * 作    者：fantianwen
 * 时    间：2019/2/16  2:46 PM
 */

class CustomConverterFactory(private val mGson: Gson) : Converter.Factory() {

    companion object {

        fun create(): CustomConverterFactory {
            return create(Gson())
        }

        fun create(gson: Gson): CustomConverterFactory {
            return CustomConverterFactory(gson)
        }

    }


    override fun requestBodyConverter(
        type: Type,
        parameterAnnotations: Array<Annotation>,
        methodAnnotations: Array<Annotation>,
        retrofit: Retrofit
    ): Converter<*, RequestBody>? {
        val adapter = mGson.getAdapter(TypeToken.get(type))
        return GsonRequestBodyConverter(mGson, adapter!!)
    }


    override fun responseBodyConverter(
        type: Type,
        annotations: Array<Annotation>,
        retrofit: Retrofit
    ): Converter<ResponseBody, *>? {
        return GsonResponseBodyConverter<Any>(mGson, type)
    }
}


private class GsonRequestBodyConverter<T>(val mGson: Gson, val mAdapter: TypeAdapter<T>) :
    Converter<T, RequestBody> {

    companion object {
        private val MEDIA_TYPE = "application/json; charset=UTF-8".toMediaTypeOrNull()
        private val UTF_8 = Charset.forName("UTF-8")
    }


    override fun convert(value: T): RequestBody {
        val buffer = Buffer()
        val writer = OutputStreamWriter(buffer.outputStream(), UTF_8)
        val jsonWriter = mGson.newJsonWriter(writer)
        mAdapter.write(jsonWriter, value)
        jsonWriter?.close()
        return RequestBody.create(MEDIA_TYPE, buffer.readByteString())
    }

}

private class GsonResponseBodyConverter<T>(val mGson: Gson, val mType: Type) :
    Converter<ResponseBody, T> {
    override fun convert(value: ResponseBody): T? {
        value.use {
            val response = it.string()
            val result = mGson.fromJson(response, Response::class.java)
            when (result.code.toInt() != 0) {
                true -> {
                    throw ApiException(result.code, result.message!!)
                }
                else -> {
                    return mGson.fromJson(response, mType)
                }
            }
        }
    }

}